<?php

namespace App\Repository;

use App\Entity\AdminModule;
use App\Entity\AdminUserGroup;
use App\Utils\Base\FilterBase;
use App\Utils\Enum\CommonEnum;
use App\Utils\Enum\RedisKeyEnum;
use App\Service\RedisService;
use App\Utils\Filter\Admin\User\AdminUserGroupFilter;
use App\Utils\Traits\FilterTrait;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Symfony\Contracts\Cache\CacheInterface;
use Symfony\Contracts\Cache\ItemInterface;
use Doctrine\Persistence\ManagerRegistry;

/**
 * @method AdminUserGroup|null find($id, $lockMode = null, $lockVersion = null)
 * @method AdminUserGroup|null findOneBy(array $criteria, array $orderBy = null)
 * @method AdminUserGroup[]    findAll()
 * @method AdminUserGroup[]    findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
 */
class AdminUserGroupRepository extends ServiceEntityRepository {
    use FilterTrait;

    public $redis;
    public $cache;

    public function __construct (ManagerRegistry $registry, RedisService $redis, CacheInterface $cache) {
        parent::__construct($registry, AdminUserGroup::class);
        $this->redis = $redis->redis;
        $this->cache = $cache;
    }

    /**
     * User: Gao
     * Date: 2020/3/21
     * Description: 获取用户组关联的模块集合
     * @param $id
     * @return array|mixed
     */
    public function getAdminModuleSonataAdmins ($id) {
        $admin_modules = [];

        $obj = $this->find($id);
        if (is_object($obj)) {
            $module_ids = json_decode($obj->getModuleIds(), true);
            $admin_modules = $this->createQueryBuilder('a')
                ->select('a.sonata_admin')
                ->where('a.status = :status')
                ->andWhere('a.id in (:ids)')
                ->andWhere('a.pid != 0')
                ->setParameter('status', true)
                ->setParameter('ids', $module_ids)
                ->getQuery()
                ->getArrayResult();
        }

        return $admin_modules;
    }

    /**
     * User: Gao
     * Date: 2020/3/21
     * Description: 获取指定用户组对应模块集
     * @param AdminUserGroup $admin_user_group
     * @param bool $is_refresh
     * @return array|mixed
     */
    public function getAdminModuleByAdminUserGroup (AdminUserGroup $admin_user_group, $is_refresh = false) {
        $result = [];

        $redis_key = RedisKeyEnum::REDIS_ADMIN_USER_GROUP_KEY.$admin_user_group->getId();
        $redis_admin_user_group_data = $this->redis->get($redis_key);
        if (is_null($redis_admin_user_group_data) || $is_refresh) {
            $admin_module_ids = json_decode($admin_user_group->getModuleIds(), true);
            $result = $this->getEntityManager()->getRepository(AdminModule::class)->getModules($admin_module_ids);
            $this->redis->setex($redis_key, 600, serialize($result));
        } else {
            $result = unserialize($redis_admin_user_group_data);
        }

        return $result;
    }

    /**
     * User: Gao
     * Date: 2020/3/22
     * Description: 获取对应用户组关联的用户数
     * @param array $id
     * @return int
     * @throws \Doctrine\ORM\NoResultException
     * @throws \Doctrine\ORM\NonUniqueResultException
     */
    public function getAdminUserCount ($id = []) {
        $result = $this->getEntityManager()
            ->createQuery('SELECT count(a) as count FROM App\Entity\AdminUser a where a.admin_user_group_id in (:admin_user_group_id)')
            ->setParameter('admin_user_group_id', $id)
            ->getSingleResult();

        return $result['count'] ?? 0;
    }

    /**
     * 获取对应的admin_module中的模块集合
     * @param $id
     * @param bool $is_refresh
     * @return array|mixed
     * @throws \Exception
     */
    public function getAuthSignsById ($id, $is_refresh = false) {
        $result = [];

        $admin_user_group = $this->find($id);
        $redis_key = RedisKeyEnum::REDIS_ADMIN_USER_GROUP_KEY.$id.':auth_signs';
        if (is_object($admin_user_group)) {
            $redis_sonata_admin_data = $this->redis->get($redis_key);
            if (is_null($redis_sonata_admin_data) || $is_refresh) {
                $ids = json_decode($admin_user_group->getModuleIds(), true);
                $result = $this->getEntityManager()->getRepository(AdminModule::class)->getAuthSigns($ids);
                $this->redis->setex($redis_key, 600, serialize($result));
            } else {
                $result = unserialize($redis_sonata_admin_data);
            }
        } else {
            $this->redis->del($redis_key);
        }

        return $result;
    }

    /**
     * 获取用户组键值对
     * @return array
     * @throws \Exception
     */
    public function getItems () {
        $result = [];
        $objs = self::findAll();
        foreach ($objs as $obj) {
            $result[$obj->getId()] = $obj->getName();
        }
        return $result;
    }

    /**
     * 获取键值对集合用于common
     * @return mixed
     * @throws \Psr\Cache\InvalidArgumentException
     */
    public function getCommonItems () {
        return $this->cache->get(CommonEnum::ADMIN_USER_GROUP_LIST_KEY, function (ItemInterface $item) {
            $objs = $this->createQueryBuilder('a')
                ->select('a.id,a.name')
                ->getQuery()
                ->getArrayResult();
            $item->expiresAfter(600);
            return $objs;
        });
    }

    /**
     * 根据ID返回用户组信息
     * @param $id
     * @return array
     * @throws \Exception
     */
    public function getOneById ($id) {
        return $this->createQueryBuilder('a')
            ->select('a.id,a.name,a.module_ids,a.is_super')
            ->where('a.id = :id')
            ->setParameter('id', $id)
            ->getQuery()
            ->getArrayResult();
    }

    /**
     * 指定用户组下是否有用户
     * @param $id
     * @return bool
     * @throws \Exception
     */
    public function hasAdminUser ($id): bool {
        $result = false;

        $total = $this->getEntityManager()->createQueryBuilder()
            ->select('count(a.id) as total')
            ->where('a.admin_user_group_id = :admin_user_group_id')
            ->from('App:AdminUser', 'a')
            ->setParameter('admin_user_group_id', $id)
            ->getQuery()
            ->getSingleScalarResult();
        if ($total > 0) {
            $result = true;
        }

        return $result;
    }

    /**
     * 获取字段和对应值并且不等于ID值的数据
     * @param $field
     * @param $value
     * @param $id
     * @return mixed
     * @throws \Exception
     */
    public function findOneByFieldAndNotId ($field, $value, $id) {
        return $this->createQueryBuilder('a')
            ->where('a.id != :id')
            ->andWhere('a.'.$field.' = :field')
            ->setParameter('id', $id)
            ->setParameter('field', $value)
            ->getQuery()
            ->getOneOrNullResult();
    }

    /**
     * 查询
     * @param array $params
     * @return array|int|string
     */
    public function search ($params = []) {
        $page = $params['page'] ?? 1;
        $limit = $params['limit'] ?? 10;
        return $this->filter(new AdminUserGroupFilter($params))
            ->select(FilterBase::ALIAS.'.id,'.FilterBase::ALIAS.'.name,'.FilterBase::ALIAS.'.module_ids,'.FilterBase::ALIAS.'.created_at')
            ->setFirstResult(($page - 1) * $limit)
            ->setMaxResults($limit)
            ->orderBy(FilterBase::ALIAS.'.id', 'DESC')
            ->getQuery()
            ->getArrayResult();
    }

    /**
     * 获取查询count
     * @param array $params
     * @return int|mixed|string
     */
    public function searchTotal ($params = []) {
        return $this->filter(new AdminUserGroupFilter($params))
            ->select('count('.FilterBase::ALIAS.'.id) as total')
            ->getQuery()
            ->getSingleScalarResult();
    }
}
